import * as S3 from '@aws-sdk/client-s3';
import * as fs from "fs";
import { Readable } from "stream";
import { CDNClient } from "./CDNClient";
import { CDNClientConfig } from './CDNConfigs';

export class S3CDNClient implements CDNClient {
	constructor(config: CDNClientConfig) {
		this.setConfig(config)
		this.init();
	}

	protected config!: CDNClientConfig;
	setConfig(config: CDNClientConfig) {
		this.config = config;
	}

	destroy(): Promise<boolean> {
		this.s3Client.destroy();
		return Promise.resolve(true)
	}

	protected s3Client!: S3.S3Client;
	protected createResClient(config: CDNClientConfig) {
		const s3Client = new S3.S3Client({
			credentials: {
				accessKeyId: config.accessKeyId,
				secretAccessKey: config.secretAccessKey,
			},
			// credentials: XX.fromIni({ profile: 'default' }),
			region: config.region,
			// endpoint: "https://meta-cdn-client-hoc-test.s3.cn-northwest-1.amazonaws.com.cn",
		});
		// s3Client.config.bucketEndpoint = false
		return s3Client;
	}

	protected createDefaultClient() {
		let s3Client = this.createResClient(this.config);
		this.s3Client = s3Client;
		return s3Client;
	}

	protected getOrCreateClient() {
		if (this.s3Client) {
			return this.s3Client;
		} else {
			return this.createDefaultClient();
		}
	}

	init(): CDNClient {
		this.getOrCreateClient();
		return this;
	}

	async uploadData(key: string, data: string | Buffer, readFast: boolean): Promise<string> {
		let s3Client = this.s3Client;
		let config = this.config;
		var result = await s3Client.send(new S3.PutObjectCommand({
			Bucket: config.bucket,
			Key: key,
			Body: data,
		}));
		return key
	}

	uploadFile(filepath: string, key: string, readFast: boolean): Promise<string> {
		return new Promise<string>((resolve, reject) => {
			let s3Client = this.s3Client;
			let config = this.config;
			fs.readFile(filepath, async (err, data) => {
				if (err) {
					reject(err);
					return;
				}

				try {
					let contentType = "";
					if (filepath.search(".jpg") == -1 && filepath.search(".png") == -1) {
						contentType = "text/html";
					} else {
						contentType = "image/jpeg";
					}

					const result = await s3Client.send(new S3.PutObjectCommand({
						// Bucket: "meta-cdn-client-hoc-test",
						Bucket: config.bucket,
						// Specify the name of the new object. For example, 'index.html'.
						// To create a directory for the object, use '/'. For example, 'myApp/package.json'.
						Key: key,
						// Content of the new object.
						Body: data,
						ContentType: contentType,
					}));
					console.log(`upload file success: ${filepath} -> ${key}`);
					resolve(key);
				} catch (err) {
					reject(err);
				}
			});
		});
	}
	async fetchFile(key: string): Promise<Readable> {
		let s3Client = this.s3Client;
		let config = this.config;

		let result = await s3Client.send(new S3.GetObjectCommand({
			Bucket: config.bucket,
			Key: key,
			// ResponseContentEncoding: "utf-8",
		}));
		return result.Body as Readable
	}
	async isExistObject(key: string): Promise<boolean> {
		let s3Client = this.s3Client;
		let config = this.config;

		var isFileExist = true;
		try {
			const existResult = await s3Client.send(new S3.HeadObjectCommand({
				Bucket: config.bucket,
				Key: key,
			}));
		} catch (ex) {
			if (ex instanceof S3.NotFound) {
				isFileExist = false;
			}
		}
		return isFileExist;
	}

}
